/**
 * 
 */

package com.wutianyi.nio.download;

import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.Callable;

/**
 * @author wutianyi
 * 
 */
public class DownloadClient<T> implements Callable<T> {

	private FileChannel		fileChannel;
	private static Selector	selector;
	private ByteBuffer		byteBuffer	= ByteBuffer.allocate(1024);

	private String			serverFileName;
	private String			localFileName;

	public DownloadClient(String serverFileName, String localFileName) {

		this.serverFileName = serverFileName;
		this.localFileName = localFileName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.concurrent.Callable#call()
	 */
	@Override
	public T call() throws Exception {

		if(null == selector) {
			selector = Selector.open();
		}
		SocketChannel channel = SocketChannel.open();
		channel.configureBlocking(false);
		channel.connect(new InetSocketAddress("localhost", 9090));
		channel.register(selector, SelectionKey.OP_CONNECT);

		for(;;) {
			selector.select();
			Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
			while(keyIterator.hasNext()) {
				SelectionKey key = keyIterator.next();
				keyIterator.remove();
				if(key.isConnectable()) {
					SocketChannel socketChannel = (SocketChannel)key.channel();
					if(socketChannel.isConnectionPending()) {
						socketChannel.finishConnect();
					}
					socketChannel.write(ByteBuffer.wrap(serverFileName.getBytes()));
					socketChannel.register(selector, SelectionKey.OP_READ);
				}
				if(key.isReadable()) {
					SocketChannel socketChannel = (SocketChannel)key.channel();
					byteBuffer.clear();
					if(!socketChannel.isConnected()) {
						return null;
					}
					if(null == fileChannel) {
						fileChannel = new RandomAccessFile(localFileName, "rw").getChannel();
						int r = socketChannel.read(byteBuffer);
						if(r <= 0) {
							if(null != fileChannel) {
								fileChannel.close();
							}
							channel.close();
							key.cancel();
							return null;
						}
						byteBuffer.flip();
						fileChannel.write(byteBuffer);
					}
				}
			}
		}
	}

}
